package com.alibaba.megrez.privilege;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.platform.buc.sso.common.constants.BucSSOConstants;

public class HTTPUtil {
	private static final Logger log = LoggerFactory.getLogger(HTTPUtil.class);

	public static String retrieve(String url) throws IOException, KeyManagementException, NoSuchAlgorithmException,
		NoSuchProviderException {
		return retrieve(url, null);
	}

	public static String retrieve(String url, Map<String, String> postdatas) throws IOException,
		KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
		BufferedReader r = null;
		try {
			URL u = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) u.openConnection();
			connection.setRequestProperty("Connection", "close");
			connection.setUseCaches(false);
			connection.setDoOutput(true);
			connection.setConnectTimeout(30000);
			connection.setReadTimeout(30000);
			if (postdatas != null) {
				connection.setRequestMethod("POST");// POST提交模式
				StringBuffer param = new StringBuffer();
				for (String key : postdatas.keySet()) {
					param.append(BucSSOConstants.AMPERSAND);
					param.append(key).append(BucSSOConstants.EQUALS).append(postdatas.get(key));
				}
				log.info("param :" + param);
				connection.getOutputStream().write(param.toString().getBytes());
				connection.getOutputStream().flush();
				connection.getOutputStream().close();
			}
			if ((connection instanceof sun.net.www.protocol.https.HttpsURLConnectionImpl)) {
				((sun.net.www.protocol.https.HttpsURLConnectionImpl) connection)
						.setSSLSocketFactory(createSSLSocketFactory());
				((sun.net.www.protocol.https.HttpsURLConnectionImpl) connection)
						.setHostnameVerifier(new TrustAnyHostnameVerifier());
			}
			r = new BufferedReader(new InputStreamReader(connection.getInputStream(), BucSSOConstants.ENCODING_UTF8));
			log.info("r values :{}", r);
			String temp = read(r);
			log.info("return values :{}", temp);
			return read(r);
		} finally {
			try {
				if (r != null)
					r.close();
			} catch (IOException ex) {
				// ignore
			}
		}
	}

	public static String retrieveWithErrorHandler(String url, Map<String, String> postdatas) throws IOException,
		KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
		BufferedReader r = null;
		try {
			URL u = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) u.openConnection();
			connection.setRequestProperty("Connection", "close");
			connection.setUseCaches(false);
			connection.setDoOutput(true);
			connection.setConnectTimeout(60000);
			connection.setReadTimeout(60000);
			if (postdatas != null) {
				connection.setRequestMethod("POST");// POST提交模式
				StringBuffer param = new StringBuffer();
				for (String key : postdatas.keySet()) {
					param.append(BucSSOConstants.AMPERSAND);
					param.append(key).append(BucSSOConstants.EQUALS).append(postdatas.get(key));
				}
				connection.getOutputStream().write(param.toString().getBytes());
				connection.getOutputStream().flush();
				connection.getOutputStream().close();
			}
			if ((connection instanceof sun.net.www.protocol.https.HttpsURLConnectionImpl)) {
				((sun.net.www.protocol.https.HttpsURLConnectionImpl) connection)
						.setSSLSocketFactory(createSSLSocketFactory());
				((sun.net.www.protocol.https.HttpsURLConnectionImpl) connection)
						.setHostnameVerifier(new TrustAnyHostnameVerifier());
			}
			int retCode = connection.getResponseCode();
			// receive ,用recIn判断是否需要返回流形式
			InputStream inputStream = null;
			if (retCode >= 400) {
				inputStream = connection.getErrorStream();
			} else {
				inputStream = connection.getInputStream();
			}
			String result = "";
			if (inputStream != null) {
				r = new BufferedReader(new InputStreamReader(inputStream, BucSSOConstants.ENCODING_UTF8));
				result = read(r);
			}
			return result;
		} finally {
			try {
				if (r != null)
					r.close();
			} catch (IOException ex) {
				// ignore
			}
		}
	}

	private static SSLSocketFactory createSSLSocketFactory() throws NoSuchAlgorithmException, NoSuchProviderException,
		KeyManagementException {
		SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
		sslContext.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new SecureRandom());
		return sslContext.getSocketFactory();
	}

	public static String read(Reader reader) {
		try {
			final int DEFAULT_BUFFER_SIZE = 1024 * 4;

			StringWriter writer = new StringWriter();

			char[] buffer = new char[DEFAULT_BUFFER_SIZE];
			int n = 0;
			while (-1 != (n = reader.read(buffer))) {
				writer.write(buffer, 0, n);
			}
			log.info("read writer: {}", writer);
			return writer.toString();
		} catch (IOException ex) {
			throw new IllegalStateException("read error", ex);
		}
	}

	private static class TrustAnyTrustManager implements X509TrustManager {
		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}

		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[] {};
		}
	}

	private static class TrustAnyHostnameVerifier implements HostnameVerifier {

		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	}

	public static String createUrlWithoutParam(String fullUrl, String paramName, String paramValue) {
		String keyValue = paramName + BucSSOConstants.EQUALS + paramValue;
		if (fullUrl.contains(keyValue + BucSSOConstants.AMPERSAND)) {
			fullUrl = fullUrl.replace(keyValue + BucSSOConstants.AMPERSAND, "");
		} else
			fullUrl = fullUrl.replace(keyValue, "");
		if (fullUrl.endsWith(BucSSOConstants.AMPERSAND) || fullUrl.endsWith(BucSSOConstants.QUESTION)) {
			fullUrl = fullUrl.substring(0, fullUrl.length() - 1);
		}
		return fullUrl;
	}

	public static Map<String, String> splitQueryString(String queryString) {
		Map<String, String> paramMap = new HashMap<String, String>();
		if (queryString == null)
			return paramMap;
		String[] params = queryString.split(BucSSOConstants.AMPERSAND);
		if (params != null) {
			for (String param : params) {
				if (param != null) {
					String[] kv = param.split(BucSSOConstants.EQUALS);
					if (kv != null && kv.length > 0) {
						if (kv.length >= 2)
							paramMap.put(kv[0], kv[1]);
						else
							paramMap.put(kv[0], "");
					}
				}
			}
		}
		return paramMap;
	}

	public static String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/**
	 * 对url中的
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String encodeUrl(String urlStr) throws Exception {
		if (StringUtils.isBlank(urlStr))
			return urlStr;
		URL url = new URL(urlStr);
		String queryString = url.getQuery();
		String path = url.getPath();
		String encodePath = URLEncoder.encode(path, "UTF-8").replace("%2F", "/");
		if (StringUtils.isNotBlank(queryString)) {
			Map<String, String> queries = splitQueryString(queryString);
			StringBuffer newQueryString = new StringBuffer();
			for (String key : queries.keySet()) {
				String value = queries.get(key);
				// 防止原来已是encode状态的值重复encode，如果decode后结果不一样，说明已经是encode的
				if (!value.equals(URLDecoder.decode(queries.get(key), "UTF-8"))) {
					newQueryString.append("&").append(key).append("=").append(value);
				} else{
				    newQueryString.append("&").append(key).append("=").append(URLEncoder.encode(value, "UTF-8"));
				}
					
			}
			// 移除第一个多余&
			String queryStr = newQueryString.toString().substring(1);
			urlStr = urlStr.replace(queryString, queryStr);
		}
		if (StringUtils.isNotBlank(path) && StringUtils.isNotBlank(encodePath)) {
			urlStr = urlStr.replace(path, encodePath);
		}
		return urlStr;
	}

	public static String getHost(String backUrl) {
		String host = "";
		try {
			int index = backUrl.indexOf('?');
			if (index > 0) {
				backUrl = backUrl.substring(0, index);
			}
			backUrl = URLDecoder.decode(backUrl, "UTF-8");
			URL url = new URL(backUrl);
			host = url.getHost();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return host;
	}

	public static String replaceSpecialCharacters(String url) {
		if (StringUtils.isBlank(url))
			return url;
		else
			return url.replace(" ", "%20").replace("|", "%7C").replace("{", "%7B").replace("}", "%7D");
	}

}
